#pragma once

// R is the return type
template <class R>

class FatBase
{
public:
    virtual R callMethod() = 0;
    virtual R callMethod(void* arg1) = 0;
	virtual R callMethod(void *& arg1) = 0;
    virtual R callMethod(void* arg1, void* arg2) = 0;
};

// r = return type
// o = object definition
// m = method
#define METHOD(r,o,m) (r (o::*)() )(&o::m)

// O = object definition
// R = return type
template <class O, class R>

class FatPointer : public FatBase<R>
{
    typedef R (O::*PMETHOD)();
    typedef R (O::*PMETHOD1)(void*);
    typedef R (O::*PMETHOD2)(void*, void*);

public:
    FatPointer(O* pObject, PMETHOD pMethod) : m_pObject( pObject ), m_pMethod( pMethod ) {};

    // Member Variables
private:
    O*    m_pObject;    // pointer to an object
    PMETHOD    m_pMethod;    // pointer to the method

    //Implementation
public:
    void setObject( O* pObject ) { m_pObject = pObject; }
    void setMethod( PMETHOD pMethod ) { m_pMethod = pMethod; }

    // 0 args
    virtual R callMethod()
    {
        return (m_pObject->*m_pMethod)();
    }

    // 1 arg
	virtual R callMethod(void * arg1)
    {
        return (m_pObject->*(PMETHOD1)m_pMethod)(arg1);
    }

	virtual R callMethod(void *& arg1)
    {
        return (m_pObject->*(PMETHOD1)m_pMethod)(arg1);
    }

    // 2 args
    virtual R callMethod(void* arg1, void* arg2)
    {
        return (m_pObject->*(PMETHOD2)m_pMethod)(arg1, arg2);
    }
};
